{{tag>fichier script}}

----

====== Dossier magique : classement automatique de fichiers ====== 

En 2007, sur [[http://forum.ubuntu-fr.org/viewtopic.php?id=144237|l'initiative de xelator]], quelques scripts ont été créés afin de ranger automatiquement les fichiers selon leur contenu : les .ogg avec les .ogg, les .avi avec les .avi, etc. Cela a débouché sur le script "Dossier magique" qui est présenté ici. En cas de problème merci de poster sur le sujet précédemment cité.
Le code a été remanié en 2015 par erresse, afin d'ajouter au script une interface graphique permettant de l'utiliser plus facilement sans en passer obligatoirement par la ligne de commande.

===== Fichiers reconnus =====

Actuellement, le script reconnaît (en se basant notamment sur leur type MIME) les fichiers de type texte, pdf, dvi, ps/postscript, ogg, la plupart des formats audio,la plupart des formats vidéo, flash, ASF, la plupart des formats image, les archives tar, rar et zip/gzip, les scripts shell, les documents MS-Word, et les fichiers LaTeX. N'hésitez pas à en rajouter (en le signalant sur le forum, merci...).


===== Le script =====

Copiez-collez le script suivant dans un fichier, que vous appellerez par exemple "dossier_magique" (pour faire original),  et assurez-vous que "zenity" est bien installé sur votre système. En principe zenity est inclus dans les distributions Ubuntu :

<code>
#!/bin/bash

CURRENT_VER=1.0

# initialisation des options

TERMINAL="FAUX"
AIDE="FAUX"
VERSION="FAUX"

# Définition des fonctions du script

# Test du code retour de zenity :
function testcrd()
{
	if [ ${crd} = -1 ]; then
		zenity --error --title "Dossier Magique" --text "Une erreur inattendue s'est produite. Abandon."
		exit 2
	fi
	if [ ${crd} = 1 ]; then
		zenity --info --title "Dossier Magique" --text "Vous avez choisi d'annuler le script. Sortie."
		exit 1
	fi
	return 0
}

# Déplacement d'un fichier et mise à jour du fichier log :
function bouge()
{
    mv "${1}" "${2}"
    heure=`date +%D-%H:%m`
    echo "[${heure}] "${1}" déplacé dans "${2}"" >> ${LOG}
    return 0
}

# Créons les répertoires s'ils n'existent pas :
function createdirs()
{
    mkdir -p "${TXT}"
    mkdir -p "${PDF}"
    mkdir -p "${AUDIO}"
    mkdir -p "${VIDEO}"
    mkdir -p "${IMG}"
    mkdir -p "${ARCHIVES}"
    mkdir -p "${DOCS}"
    mkdir -p "${TEX}"
    mkdir -p "${MISC}"
    mkdir -p "${BIN}"

    return 0
}

# Trions les fichiers :
function tri()
{
    cd "${1}"
    ls > /tmp/tri
    while read fichier
    do
		# Cas particulier des fichiers à traiter d'après l'extension
		type="${fichier##*.}"
		case "${type}" in
			wma) bouge "${fichier}" "${AUDIO}";;

			*)	# Utilisons si possible le type mime :
				type=`file -bi "${fichier}"`

		        case "${type}" in
		            *script*) bouge "${fichier}" "${BIN}";;
            
		            *executable*) bouge "${fichier}" "${BIN}";;
        
		            *pdf* | *dvi* | *postscript*) bouge "${fichier}" "${PDF}";;
            
		            *audio* | *ogg*) bouge "${fichier}" "${AUDIO}";;
        
		            *video* | *flash*) bouge "${fichier}" "${VIDEO}";;
    
		            *image*) bouge "${fichier}" "${IMG}";;

		            *tar* | *rar* | *zip*) bouge "${fichier}" "${ARCHIVES}";;

		            *msword* | *excel* | *powerpoint* | *rtf* | *opendocument*) bouge "${fichier}" "${DOCS}";;

					*)	# Si le type mime ne suffit pas :
				        type=`file -b "${fichier}"`

		        		case "${type}" in
		        		    *directory*) continue;;
               
		        		    *byte-compiled*) bouge "${fichier}" "${BIN}";;

				            *script*) bouge "${fichier}" "${BIN}";;
               
		        		    *LaTeX*) bouge "${fichier}" "${TEX}";;
        
		        		    *ASF*) bouge "${fichier}" "${VIDEO}";;

				            *text*) bouge "${fichier}" "${TXT}";;
    
							*)	# Le type est donc inconnu :
								bouge "${fichier}" "${MISC}";;
		        		esac
						;;
				esac
				;;
		esac
    
    done < /tmp/tri

    return 0
}

# Testons d'abord si le script est lancé en mode terminal
while getopts ":agtv-:" OPT
do
    # gestion des options longues avec ou sans argument
    [ $OPT = "-" ] && case "${OPTARG%%=*}" in
        aide) OPT="a" ;;
        graphique) OPT="g" ;;
        terminal) OPT="t" ;;
        version) OPT="v" ;;
        *) echo "Option inconnue" ; exit 1 ;;
    esac
    # puis gestion des options courtes
    case $OPT in
        g) TERMINAL="FAUX" ;;
        a) AIDE="VRAI" ;;
        t) TERMINAL="VRAI" ;;
        v) VERSION="VRAI" ;;
        *) echo "Option inconnue" ; exit 1 ;;
    esac
done 

# Aide

if [ "$AIDE" = "VRAI" ]
then
	echo "Syntaxe 1 : avec 0 ou 1 option et sans paramètre."
	echo "            $0					Mode graphique."
	echo "            $0 -g | --graphique	Mode graphique."
	echo "            $0 -a | --aide		Affiche l'aide."
	echo "            $0 -v | --version		Affiche la version."
    echo "Syntaxe 2 : en mode terminal avec paramètre(s) obligatoire(s)."
	echo "            $0 -t | --terminal CIBLE [SOURCE1 ... SOURCEn]"
	echo "            où CIBLE est le dossier résultant classé"
	echo "            et SOURCE(s) le(s) dossier(s) vrac à trier."
	echo "            Si SOURCE est omis, alors CIBLE=SOURCE."
    exit 0
fi

# Version

if [ "$VERSION" = "VRAI" ]
then
    echo " "
    echo "Version $0 : $CURRENT_VER"
#    head -15 $0 | grep -v bash
    exit 0
fi

# Mémorisons le répertoire courant
OLDDIR=`pwd`
# Initialisons le dossier racine CIBLE
DIR="${HOME}"
# Définissons le fichier de log (aucun par défaut)
LOG="/dev/null"

# Option "terminal" pour utilisation non graphique
if [ "$TERMINAL" = "VRAI" ]
then
	# On élimine les options pour charger le(s) paramètre(s)
	shift
	if [ "${1}" = "" ]
	then
		echo "En mode terminal, indiquer obligatoirement le(s) paramètre(s)"
		exit 1
	fi
# Sinon, exécution en mode graphique
else
	# On affiche d'abord une fenêtre d'aide à l'utilisateur
	echo "- Vous allez tout d'abord choisir le dossier dans lequel seront créés" > /tmp/notice
	echo "  les sous-dossiers où classer les fichiers triés. C'est le dossier CIBLE." >> /tmp/notice
	echo "- Vous sélectionnerez ensuite le(s) dossier(s) ''en vrac'' dont vous" >> /tmp/notice
	echo "  voulez classer les fichiers. C'est (ce sont) le(s) dossier(s) SOURCE." >> /tmp/notice
	echo "- Note : Le dossier CIBLE peut être le même que le dossier SOURCE," >> /tmp/notice
	echo "  si les fichiers sont tous dans un même dossier. Dans ce cas, on ne" >> /tmp/notice
	echo "  peut avoir qu'un seul dossier SOURCE, qui est également la CIBLE..." >> /tmp/notice
	echo "*** Vous pouvez cliquer sur ''Annuler'' pour mettre fin au script ***" >> /tmp/notice
	zenity --text-info --title "Dossier Magique - Mode d'emploi" --height "260" --width "490" --filename "/tmp/notice"
	crd=$?; testcrd
fi

# Option "terminal" pour utilisation non graphique
if [ "$TERMINAL" = "VRAI" ]
then
	DIR="${1}"
# Sinon, exécution en mode graphique
else
	# On sélectionne d'abord le répertoire cible
	DIR=$(zenity --file-selection --title "Dossier Magique - Choisir répertoire CIBLE" --filename "$DIR"/ --directory)
	crd=$?; testcrd
fi


# Option "graphique" ou par défaut pour utilisation graphique
if [ "$TERMINAL" = "FAUX" ]
then
	# Protégeons le séparateur standard et initialisons-le à "|"
	OLDIFS="${IFS}"
	IFS='|'
fi
# Option "terminal" pour utilisation non graphique
if [ "$TERMINAL" = "VRAI" ]
then
	# On recherche le(s) paramètre(s) SOURCE(S) éventuel(s)
	shift
	if [ "${1}" = "" ]
	then
		# Pas de répertoire SOURCE, alors SOURCE = CIBLE
		TABSCE=("$DIR")
	else
		# On charge le (la liste des) dossier(s) SOURCE(S)
		TABSCE=("${@}")
	fi
# Sinon, exécution en mode graphique
else
	# On peut sélectionner un ou plusieurs répertoires à trier
	# (par défaut, on trie dans le même répertoire cible=source)
	TABSCE=($(zenity --file-selection --title "Dossier Magique - Choisir répertoire(s) SOURCE" --filename "$DIR"/ --directory --multiple))
	crd=$?; testcrd
fi

# Définition des répertoires (à adapter si besoin) :
TXT="${DIR}/Documents"
PDF="${DIR}/Documents"
AUDIO="${DIR}/Musique"
VIDEO="${DIR}/Vidéos"
IMG="${DIR}/Images"
ARCHIVES="${DIR}/Archives"
DOCS="${DIR}/Documents"
TEX="${DIR}/Documents"
MISC="${DIR}/Divers"
BIN="${DIR}/Exécutables"

# Création des répertoires de tri dans le dossier cible
createdirs
for SCE in "${TABSCE[@]}"
do
	# Option "terminal" pour utilisation non graphique
	if [ "$TERMINAL" = "VRAI" ]
	then
		tri "${SCE}"
	else
        tri "${SCE}" | zenity --progress --title "Dossier Magique - Transfert en cours" --auto-close --pulsate --no-cancel
	fi
done

# Restaurons le séparateur et le répertoire courant
IFS="${OLDIFS}"
cd "${OLDDIR}"

# Option "graphique" ou par défaut pour utilisation graphique
if [ "$TERMINAL" = "FAUX" ]
then
	# Restaurons le séparateur standard
	IFS="${OLDIFS}"
	# Nettoyons les fichiers temporaires générés
	rm /tmp/notice /tmp/tri

	zenity --info --title "Dossier Magique" --text "Traitement terminé" --timeout "5"
fi

exit 0
</code>

Enregistrez ce fichier dans un dossier de votre $HOME et rendez-le exécutable.
- En console :
  chmod +x /chemin/vers/le/fichier/dossier_magique
- En graphique avec le navigateur : clic droit sur le fichier > propriétés > permissions, et cochez la case "Exécution, autoriser l'exécution du fichier comme un programme".

===== Adaptation =====


==== Répertoires ====

<note importante>
Ce script crée une série de sous-dossiers dans le dossier CIBLE. Si certains sous-dossiers existent déjà, ils ne seront pas re-créés ni vidés de leur contenu, les nouveaux fichiers y seront simplement ajoutés.
Si vous désirez nommer différemment les sous-dossiers créés par le script, vous pouvez adapter les définitions des répertoires.
</note>

Les dossiers par défaut existent sous les versions récentes d'Ubuntu dans $HOME, à l'exception des dossiers Divers, Exécutables et Archives.

==== Types de fichier ====

Pour supprimer par exemple les fichiers de type rar, il suffit de modifier la ligne :
<code>*tar* | *rar* | *zip*) bouge ${fichier} ${ARCHIVES};;</code>
en :
<code>*tar* | *zip*) bouge ${fichier} ${ARCHIVES};;</code>

De même, pour rajouter un type de fichier, il suffit d'adapter ou de créer la ligne correspondante. Les types de fichiers sont reconnus grâce à la commande **file**, donc pour savoir quoi rajouter un petit test s'impose :
  file -bi un_fichier.test


===== Utilisation =====

**En ligne de commande :**
Le script accepte une option (longue --option ou courte -o) et un ou plusieurs paramètres.
Les options sont, respectivement :
   [--terminal ou -t]     --> Le script est lancé en ligne de commande
   [--graphique ou -g] ou rien     --> Le script est lancé en mode graphique. Il ne prend pas de paramètre sur la ligne
   [--version ou -v]     --> Affiche la version courante du script. Pas de paramètre
   [--aide ou -a]     --> Affiche un bref rappel d'aide pour l'utilisation. Pas de paramètre
Exemple :
   ./dossier_magique -t | --terminal CIBLE SOURCE1 SOURCE2 ...
(où CIBLE, SOURCE1 ... SOURCEn sont des répertoires. CIBLE est le dossier "racine" résultant, SOURCE(s) les dossiers à classer.
Si seul le répertoire CIBLE est spécifié, c'est ce répertoire qui sera classé par défaut. Dans ce cas, CIBLE = SOURCE.

Si les noms des répertoires contiennent des espaces et autres caractères spéciaux, mettez-les systématiquement entre guillemets et si vous référencez le dossier personnel (~/dossier/) dans le chemin, ne l'incluez pas dans les guillemets :
   ./dossier_magique -t "répertoire CIBLE" ~/dossier/"répertoire SOURCE" ...

**En mode graphique :**
En mode graphique, ne spécifiez ni paramètre ni option (ou -g | --graphique qui est la valeur par défaut). Le script affiche une petite fenêtre d'aide, puis demande au fur et à mesure les dossiers à traiter : D'abord la "racine" CIBLE, unique, puis le(s) dossier(s) SOURCE(s) à classer.
Si vous voulez classer le dossier CIBLE lui-même, ne choisissez pas d'autre dossier pour la SOURCE, dans ce cas, CIBLE = SOURCE.
Si vous devez abandonner le script en cours de route (un doute sur le travail à exécuter...), cliquez simplement sur "Annuler" pour l'interrompre sans rien effectuer.

===== Fichier de log =====

Par défaut, il n'y a pas de fichier de log. Il suffit de modifier la ligne
  LOG=/dev/null
par
  LOG=chemin_du_fichier_voulu
pour garder une trace de tout mouvement de fichier dû au script.

===== Exécution automatique =====

Il est toujours possible, en lançant une exécution en ligne de commande, de faire fonctionner le script en exécution automatique.
Pour exécuter automatiquement le script toutes les 5 minutes, par exemple, vous pouvez utiliser [[:cron|crontab]]. On édite la crontab :
  crontab -e

Et on rajoute :
<code>*/5 * * * * /chemin/vers/dossier_magique -t CIBLE [SOURCE...]</code>